import tkinter as tk
from tkinter import messagebox, scrolledtext
import cProfile
import pstats
from io import StringIO
import unittest
from unittest.mock import mock_open, patch
import os

def text_statistics_gui():
    # 创建主窗口
    root = tk.Tk()
    root.title("文本统计工具（含性能测试与单元测试）")
    root.geometry("600x500")
    root.resizable(False, False)

    # 初始化统计变量
    c_str_count = tk.IntVar(value=0)
    w_word_count = tk.IntVar(value=0)
    c_sen_count = tk.IntVar(value=0)

    # ---------------------- 核心统计功能（独立函数便于测试） ----------------------
    def count_chars_and_sentences(content):
        """统计字符数和句子数（独立函数，便于单元测试）"""
        char_count = 0
        sen_count = 0
        for t in content:
            char_count += 1
            if t in ('.', '!', '?'):
                sen_count += 1
        return char_count, sen_count

    def count_words(content):
        """统计单词数（独立函数，便于单元测试）"""
        word_count = 0
        for t in content:
            if t in (' ', ',', '.', '!', '?'):
                word_count += 1
        return word_count

    # ---------------------- 文件读取与统计 ----------------------
    def count_cfile():
        try:
            with open(r"D:\code\two\cfile.txt", "r", encoding="utf-8") as fp:
                content = fp.read()
                char_count, sen_count = count_chars_and_sentences(content)
                c_str_count.set(char_count)
                c_sen_count.set(sen_count)
        except FileNotFoundError:
            messagebox.showerror("错误", "cfile.txt文件未找到，请检查路径：D:\\code\\two\\cfile.txt")
        except Exception as e:
            messagebox.showerror("错误", f"读取cfile.txt失败：{str(e)}")

    def count_wfile():
        try:
            with open(r"D:\code\two\wfile.txt", "r", encoding="utf-8") as fp:
                content = fp.read()
                word_count = count_words(content)
                w_word_count.set(word_count)
        except FileNotFoundError:
            messagebox.showerror("错误", "wfile.txt文件未找到，请检查路径：D:\\code\\two\\wfile.txt")
        except Exception as e:
            messagebox.showerror("错误", f"读取wfile.txt失败：{str(e)}")

    def auto_count():
        count_cfile()
        count_wfile()

    # ---------------------- 性能测试功能 ----------------------
    def run_performance_test():
        profiler = cProfile.Profile()
        profiler.enable()
        for _ in range(100):
            count_cfile()
            count_wfile()
        profiler.disable()

        result_stream = StringIO()
        sort_by = "cumulative"
        stats = pstats.Stats(profiler, stream=result_stream).sort_stats(sort_by)
        stats.print_stats(20)

        result_window = tk.Toplevel(root)
        result_window.title("性能测试结果")
        result_window.geometry("800x600")

        scrollbar = tk.Scrollbar(result_window)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        result_text = tk.Text(
            result_window,
            wrap=tk.NONE,
            yscrollcommand=scrollbar.set,
            font=("Consolas", 10)
        )
        result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.config(command=result_text.yview)

        result_text.insert(tk.END, result_stream.getvalue())
        result_text.config(state=tk.DISABLED)

    # ---------------------- 单元测试功能 ----------------------
    class TestTextStatistics(unittest.TestCase):
        """文本统计功能单元测试用例"""

        def test_char_count_basic(self):
            """测试基本字符统计"""
            self.assertEqual(count_chars_and_sentences("abc")[0], 3)

        def test_sentence_count_basic(self):
            """测试基本句子统计"""
            self.assertEqual(count_chars_and_sentences("Hello!World?")[1], 2)

        def test_empty_content(self):
            """测试空内容统计"""
            chars, sens = count_chars_and_sentences("")
            self.assertEqual(chars, 0)
            self.assertEqual(sens, 0)

        def test_word_count_basic(self):
            """测试基本单词统计"""
            self.assertEqual(count_words("Hello world,test!"), 3)

        def test_word_count_with_multiple_separators(self):
            """测试多分隔符情况下的单词统计"""
            self.assertEqual(count_words("a,, b  .c!d?"), 4)

        def test_special_characters(self):
            """测试特殊字符统计"""
            self.assertEqual(count_chars_and_sentences("!@#$%^&*()")[0], 10)

        @patch('builtins.open', new_callable=mock_open, read_data="Mock content.")
        def test_file_reading(self, mock_file):
            """测试文件读取逻辑（使用mock）"""
            with open("test.txt", "r") as f:
                content = f.read()
            self.assertEqual(content, "Mock content.")

    def run_unit_tests():
        """运行单元测试并显示结果"""
        # 创建测试套件
        suite = unittest.TestLoader().loadTestsFromTestCase(TestTextStatistics)
        
        # 运行测试并捕获结果
        result_stream = StringIO()
        runner = unittest.TextTestRunner(stream=result_stream, verbosity=2)
        result = runner.run(suite)

        # 显示测试结果窗口
        test_window = tk.Toplevel(root)
        test_window.title("单元测试结果")
        test_window.geometry("800x600")

        # 添加滚动文本框
        text_area = scrolledtext.ScrolledText(
            test_window,
            wrap=tk.WORD,
            font=("Consolas", 10)
        )
        text_area.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)

        # 插入测试结果
        result_text = result_stream.getvalue()
        text_area.insert(tk.END, result_text)
        
        # 显示汇总信息
        summary = f"\n测试总结：共{result.testsRun}个用例，"
        summary += f"成功{result.testsRun - len(result.failures) - len(result.errors)}个，"
        summary += f"失败{len(result.failures)}个，"
        summary += f"错误{len(result.errors)}个"
        text_area.insert(tk.END, summary)
        
        text_area.config(state=tk.DISABLED)

    # ---------------------- 界面组件 ----------------------
    tk.Label(root, text="文本统计结果", font=("微软雅黑", 14, "bold")).pack(pady=20)

    result_frame = tk.Frame(root, bd=2, relief=tk.GROOVE, padx=20, pady=10)
    result_frame.pack(fill=tk.X, padx=50)

    tk.Label(result_frame, text="cfile.txt 统计：", font=("微软雅黑", 11, "bold")).grid(row=0, column=0, columnspan=2, pady=10, sticky=tk.W)
    tk.Label(result_frame, text="字符数：", font=("微软雅黑", 10)).grid(row=1, column=0, padx=30, pady=8, sticky=tk.W)
    tk.Label(result_frame, textvariable=c_str_count, font=("微软雅黑", 10), width=15, bg="#e0e0e0").grid(row=1, column=1, pady=8, sticky=tk.W)
    tk.Label(result_frame, text="句子数：", font=("微软雅黑", 10)).grid(row=2, column=0, padx=30, pady=8, sticky=tk.W)
    tk.Label(result_frame, textvariable=c_sen_count, font=("微软雅黑", 10), width=15, bg="#e0e0e0").grid(row=2, column=1, pady=8, sticky=tk.W)

    tk.Label(result_frame, text="wfile.txt 统计：", font=("微软雅黑", 11, "bold")).grid(row=3, column=0, columnspan=2, pady=10, sticky=tk.W)
    tk.Label(result_frame, text="单词数：", font=("微软雅黑", 10)).grid(row=4, column=0, padx=30, pady=8, sticky=tk.W)
    tk.Label(result_frame, textvariable=w_word_count, font=("微软雅黑", 10), width=15, bg="#e0e0e0").grid(row=4, column=1, pady=8, sticky=tk.W)

    # 按钮框架（新增单元测试按钮）
    btn_frame = tk.Frame(root, pady=20)
    btn_frame.pack()
    tk.Button(btn_frame, text="刷新统计", command=auto_count, width=12).grid(row=0, column=0, padx=10)
    tk.Button(btn_frame, text="性能测试", command=run_performance_test, width=12, bg="#4CAF50", fg="white").grid(row=0, column=1, padx=10)
    tk.Button(btn_frame, text="单元测试", command=run_unit_tests, width=12, bg="#2196F3", fg="white").grid(row=0, column=2, padx=10)  # 新增测试按钮
    tk.Button(btn_frame, text="退出", command=root.quit, width=12).grid(row=0, column=3, padx=10)

    auto_count()
    root.mainloop()

if __name__ == "__main__":
    text_statistics_gui()